/*
 * Copyright 2011-2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.rivoli.model.classhierarchy

import com.googlecode.rivoli.RivoliException
import com.googlecode.rivoli.model.AttributeDescriptor
import com.googlecode.rivoli.model.ElementDescriptor
import com.googlecode.rivoli.model.Model
import com.googlecode.rivoli.model.classhierarchy.hierarchies.parents.attributes.HorizontalOrientation
import com.googlecode.rivoli.model.classhierarchy.hierarchies.renderers.annotation.ParagraphRenderer

import org.testng.annotations.Test

class ClassHierarchyModelTest {
	@Test
	void 'hierarchy with single class should result in model with single element descriptor'() {
		assert createModel('single').elementDescriptors*.name == ['letter']
	}

	@Test
	void 'properties should be exposed as attribute descriptors'() {
		Model model = createModel('attributes')

		ElementDescriptor reportDescriptor = model.elementDescriptors.toList().first()
		assert reportDescriptor.attributeDescriptors.size() == 2

		AttributeDescriptor authorDescriptor = reportDescriptor.findAttributeDescriptor('author')
		assert authorDescriptor.name == 'author'
		assert authorDescriptor.type == String

		AttributeDescriptor dateDescriptor = reportDescriptor.findAttributeDescriptor('date')
		assert dateDescriptor.name == 'date'
		assert dateDescriptor.type == Date
	}

	@Test
	void 'superclass should become parent of element descriptor'() {
		Model model = createModel('parents.single')

		assert model.elementDescriptors.size() == 3

		ElementDescriptor listDescriptor = model.elementDescriptors.find {it.name == 'list'}
		assert !listDescriptor.parent

		ElementDescriptor orderedListDescriptor = model.elementDescriptors.find {it.name == 'ordered list'}
		assert orderedListDescriptor.parent == listDescriptor

		ElementDescriptor unorderedListDescriptor = model.elementDescriptors.find {it.name == 'unordered list'}
		assert unorderedListDescriptor.parent == listDescriptor
	}

	@Test(expectedExceptions = RivoliException)
	void 'superclass outside model should not be supported'() {
		createModel('parents.external')
	}

	@Test
	void 'attribute descriptors should not be inherited from parent'() {
		Model model = createModel('parents.attributes')

		assert model.elementDescriptors.size() == 2

		ElementDescriptor structureDescriptor = model.elementDescriptors.find {it.name == 'structure'}
		assert structureDescriptor.attributeDescriptors.size() == 1

		AttributeDescriptor horizontalAlignmentDescriptor = structureDescriptor.findAttributeDescriptor('horizontal alignment')
		assert horizontalAlignmentDescriptor.name == 'horizontal alignment'
		assert horizontalAlignmentDescriptor.type == HorizontalOrientation

		ElementDescriptor paragraphDescriptor = model.elementDescriptors.find {it.name == 'paragraph'}
		assert paragraphDescriptor.attributeDescriptors.empty
	}

	@Test
	void 'container property should not result in attribute descriptor'() {
		Model model = createModel('containers.property')

		ElementDescriptor tableRowDescriptor = model.elementDescriptors.find {it.name == 'table row'}
		assert !tableRowDescriptor.findAttributeDescriptor('children')
	}

	@Test
	void 'defining a container should be possible using property'() {
		Model model = createModel('containers.property')

		assert model.elementDescriptors.size() == 2

		ElementDescriptor tableRowDescriptor = model.elementDescriptors.find {it.name == 'table row'}
		ElementDescriptor tableCellDescriptor = model.elementDescriptors.find {it.name == 'table cell'}

		assert tableRowDescriptor.containerFor == tableCellDescriptor
	}

	@Test(expectedExceptions = RivoliException)
	void 'container for classes outside model should not be supported'() {
		createModel('containers.external')
	}

	@Test(expectedExceptions = RivoliException)
	void 'container for unknown classes should not be supported'() {
		createModel('containers.mistyped')
	}

	@Test(expectedExceptions = RivoliException)
	void 'container for multiple element types should not be supported'() {
		createModel('containers.multiple')
	}

	@Test
	void 'model should discover renderers'() {
		Model model = createModel('renderers.annotation')

		ElementDescriptor paragraphDescriptor = model.elementDescriptors.find {it.name == 'paragraph'}
		assert paragraphDescriptor.getRenderer(ParagraphRenderer)
	}

	@Test(expectedExceptions = RivoliException)
	void 'renderers for elements outside model should not be supported'() {
		createModel('renderers.external')
	}

	private Model createModel(String type) throws RivoliException {
		Model model = new ClassHierarchyModel()
		model.init((ClassHierarchyModel.PACKAGE_NAME): "com.googlecode.rivoli.model.classhierarchy.hierarchies.${type}")
		model
	}
}